<!--
  文件级注释：
  平台首页（Dashboard）组件。
  目标：以简洁布局展示平台核心数据统计，并对接后端报表与统计接口。
  说明：
  - 所有接口调用仅在返回值 code === 0 时视为成功。
  - 仅在 H5 项目中编写与修改代码。
  - 展示数据包括：今日营业额与结构、期间汇总指标、渠道统计、收款码排行榜、趋势统计等。
  参数：无（通过内部筛选条件触发加载）。
  返回值：无（渲染 UI）。
  异常：组件内捕获并记录错误信息，用于在界面上提示。
-->
<template>
  <div class="dashboard">
    <header class="header">
      <div class="title">平台数据总览</div>
      <div class="filters">
        <label class="field">
          <span>报表类型</span>
          <select v-model="filters.reportFormType" @change="onFiltersChange">
            <option :value="0">日报表</option>
            <option :value="1">周报表</option>
            <option :value="2">月报表</option>
          </select>
        </label>
        <label class="field">
          <span>查询日期</span>
          <input type="date" v-model="filters.selectDate" @change="onFiltersChange" />
        </label>
        <label class="field">
          <span>商户ID</span>
          <input type="text" v-model="filters.merchantId" placeholder="可选" />
        </label>
        <label class="field">
          <span>门店ID</span>
          <input type="text" v-model="filters.storeId" placeholder="可选" />
        </label>
        <button class="btn" @click="reloadAll">刷新</button>
      </div>
    </header>

    <!-- 平台净营收模块 -->
    <section class="section">
      <div class="section-title">平台净营收</div>
      <div v-if="loadingPlatform" class="loading">加载中...</div>
      <div v-else-if="errorPlatform" class="error">{{ errorPlatform }}</div>
      <div v-else-if="platform" class="cards">
        <div class="card emphasis accent-primary">
          <div class="card-label"><span class="card-icon">📈</span> 平台净营收</div>
          <div class="card-value">{{ fmtMoney(platform.SumAmount) }}</div>
          <div class="card-sub">佣金：{{ fmtMoney(platform.Commission) }}；服务费：{{ fmtMoney(platform.PlatformServiceFee) }}；提现手续费：{{ fmtMoney(platform.WithdrawalFee) }}</div>
        </div>
      </div>
      <div v-else class="empty">暂无数据</div>
    </section>

    <!-- 今日营业额与结构 -->
    <section class="section">
      <div class="section-title">今日营业额</div>
      <div v-if="loadingToday" class="loading">加载中...</div>
      <div v-else-if="errorToday" class="error">{{ errorToday }}</div>
      <div v-else-if="today" class="cards">
        <div class="card emphasis accent-primary">
          <div class="card-label"><span class="card-icon">💰</span> 今日营业额</div>
          <div class="card-value">{{ fmtMoney(today.TodayTurnover) }}</div>
          <div class="card-sub">收款笔数：{{ fmtNumber(today.TodayTurnoverCount) }}</div>
        </div>
        <div class="card accent-danger">
          <div class="card-label"><span class="card-icon">💸</span> 退款金额</div>
          <div class="card-value">{{ fmtMoney(today.RefundAmount) }}</div>
          <div class="card-sub">退款笔数：{{ fmtNumber(today.RefundAmountCount) }}</div>
        </div>
        <div class="card accent-info">
          <div class="card-label"><span class="card-icon">👥</span> 顾客数</div>
          <div class="card-value">{{ fmtNumber(today.CustomerCount) }}</div>
        </div>
        <div class="card accent-success">
          <div class="card-label"><span class="card-icon">🏪</span> 直接营收</div>
          <div class="card-value">{{ fmtMoney(today.DirectRevenue) }}</div>
          <div class="card-sub">{{ fmtNumber(today.DirectRevenueCount) }} 笔</div>
        </div>
        <div class="card accent-teal">
          <div class="card-label"><span class="card-icon">🤝</span> 合作营收</div>
          <div class="card-value">{{ fmtMoney(today.CooperativeRevenue) }}</div>
          <div class="card-sub">{{ fmtNumber(today.CooperativeRevenueCount) }} 笔</div>
        </div>
        <div class="card accent-warning">
          <div class="card-label"><span class="card-icon">🏷️</span> 折扣营收</div>
          <div class="card-value">{{ fmtMoney(today.DiscountedRevenue) }}</div>
          <div class="card-sub">{{ fmtNumber(today.DiscountedRevenueCount) }} 笔</div>
        </div>
        <div class="card accent-indigo">
          <div class="card-label"><span class="card-icon">🎫</span> 合作折扣营收</div>
          <div class="card-value">{{ fmtMoney(today.CooperativeDiscountedRevenue) }}</div>
          <div class="card-sub">{{ fmtNumber(today.CooperativeDiscountedRevenueCount) }} 笔</div>
        </div>
      </div>
      <div v-else-if="!today" class="empty">暂无数据</div>
    </section>

    <!-- 期间汇总指标（日报/周报/月报） -->
    <section class="section">
      <div class="section-title">期间汇总</div>
      <div v-if="loadingReport" class="loading">加载中...</div>
      <div v-else-if="errorReport" class="error">{{ errorReport }}</div>
      <div v-else-if="report" class="cards">
        <div class="card emphasis accent-primary">
          <div class="card-label"><span class="card-icon">💰</span> 净收金额（实收）</div>
          <div class="card-value">{{ fmtMoney(report.ActualReceivedAmount) }}</div>
        </div>
        <div class="card accent-info">
          <div class="card-label"><span class="card-icon">🧾</span> 收款笔数</div>
          <div class="card-value">{{ fmtNumber(report.CollectedCount) }}</div>
        </div>
        <div class="card accent-danger">
          <div class="card-label"><span class="card-icon">💸</span> 退款金额</div>
          <div class="card-value">{{ fmtMoney(report.RefundAmount) }}</div>
          <div class="card-sub">退款笔数：{{ fmtNumber(report.RefundCount) }}</div>
        </div>
        <div class="card accent-teal">
          <div class="card-label"><span class="card-icon">🏦</span> 结算金额</div>
          <div class="card-value">{{ fmtMoney(report.SettlementAmount) }}</div>
        </div>
        <div class="card accent-warning">
          <div class="card-label"><span class="card-icon">🏷️</span> 优惠金额</div>
          <div class="card-value">{{ fmtMoney(report.CouponAmount) }}</div>
        </div>
      </div>
      <div v-else class="empty">暂无数据</div>
    </section>

    <!-- 渠道统计（替换为 ECharts 饼状占比图） -->
    <section class="section">
      <div class="section-title">渠道统计</div>
      <div v-if="report" class="panel">
        <div ref="channelChartRef" class="echart"></div>
      </div>
      <div v-else class="empty">暂无数据</div>
    </section>

    

    <!-- 趋势统计（替换为 ECharts 折线/柱状图） -->
    <section class="section">
      <div class="section-title">趋势统计</div>
      <div v-if="report" class="grid">
        <div class="panel">
          <div class="panel-title">收入趋势</div>
          <div ref="incomeChartRef" class="echart"></div>
        </div>
        <div class="panel">
          <div class="panel-title">分账对比趋势</div>
          <div ref="dividedChartRef" class="echart"></div>
        </div>
        <div class="panel">
          <div class="panel-title">优惠订单趋势</div>
          <div ref="discountChartRef" class="echart"></div>
        </div>
        <div class="panel">
          <div class="panel-title">新老顾客对比</div>
          <div ref="customerChartRef" class="echart"></div>
        </div>
      </div>
      <div v-else class="empty">暂无数据</div>
    </section>
  </div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, reactive, ref, computed, watch, nextTick } from 'vue'
import * as echarts from 'echarts'
import { PaymentService, type ReportFormRequest, type ReportFormResponse, type TodayTurnover, type PlatformHomepageResponse } from '../services/payment'
import { isSuccess } from '../services/types'

/**
 * 类级注释：筛选条件结构
 */
const filters = reactive<{ reportFormType: 0 | 1 | 2; selectDate: string; merchantId: string; storeId: string }>({
  reportFormType: 0,
  selectDate: new Date().toISOString().slice(0, 10),
  merchantId: '',
  storeId: ''
})

// 状态：今日营业额
const loadingToday = ref(false)
const errorToday = ref('')
const today = ref<TodayTurnover | null>(null)

// 状态：报表汇总
const loadingReport = ref(false)
const errorReport = ref('')
const report = ref<ReportFormResponse | null>(null)

// 状态：平台首页数据（净营收）
const loadingPlatform = ref(false)
const errorPlatform = ref('')
const platform = ref<PlatformHomepageResponse | null>(null)

/**
 * 变量级注释：图表 DOM 引用与实例
 * 说明：这些引用用于在数据就绪后初始化 ECharts，并在组件销毁时释放。
 */
const incomeChartRef = ref<HTMLDivElement | null>(null)
const dividedChartRef = ref<HTMLDivElement | null>(null)
const discountChartRef = ref<HTMLDivElement | null>(null)
const customerChartRef = ref<HTMLDivElement | null>(null)
const channelChartRef = ref<HTMLDivElement | null>(null)

let incomeChart: echarts.ECharts | null = null
let dividedChart: echarts.ECharts | null = null
let discountChart: echarts.ECharts | null = null
let customerChart: echarts.ECharts | null = null
let channelChart: echarts.ECharts | null = null

/**
 * 变量级注释：趋势图最大值（用于条形图归一化宽度）
 * @returns number 归一化所需的最大值，空数据时为 0
 */
const maxIncome = computed<number>(() => {
  const arr = report.value?.IncomeComparisonStatistics?.map(i => i.Amount || 0) || []
  return arr.length ? Math.max(...arr) : 0
})
const maxDivided = computed<number>(() => {
  const arr = report.value?.DividedAmountComparisonStatistics?.map(i => i.Amount || 0) || []
  return arr.length ? Math.max(...arr) : 0
})
const maxDiscount = computed<number>(() => {
  const arr = report.value?.DiscountedOrders?.map(i => (i.DiscountedOrderCount || 0)) || []
  return arr.length ? Math.max(...arr) : 0
})
const maxNewCust = computed<number>(() => {
  const arr = report.value?.CustomerComparisonStatistics?.map(i => (i.NewCustomerCount || 0)) || []
  return arr.length ? Math.max(...arr) : 0
})
const maxOldCust = computed<number>(() => {
  const arr = report.value?.CustomerComparisonStatistics?.map(i => (i.OldCustomerCount || 0)) || []
  return arr.length ? Math.max(...arr) : 0
})
/**
 * 变量级注释：收款码排行榜最大金额（用于条形图归一化）
 * @returns number 若排行榜为空返回 0
 */
const maxRanking = computed<number>(() => {
  const arr = report.value?.PaymentCodeRanking?.map(i => i.Amount || 0) || []
  return arr.length ? Math.max(...arr) : 0
})

/**
 * 函数级注释：将数值占比转换为百分比宽度字符串
 * @param value 当前值（可选）
 * @param max 最大值（可选，用于归一化；为 0 时返回 "0%"）
 * @returns 百分比字符串，如 "42%"
 * @throws 无显式抛出（进行边界保护）
 */
function percent(value?: number, max?: number): string {
  const v = typeof value === 'number' ? value : 0
  const m = typeof max === 'number' ? max : 0
  const pct = m > 0 ? Math.min(100, Math.round((v / m) * 100)) : 0
  return pct + '%'
}

/**
 * 函数级注释：格式化金额（分转¥）
 * @param n 金额（单位：分，允许 undefined ）
 * @returns 格式化后的人民币金额字符串，如 "¥1,234.56"
 * @throws 无显式抛出（内部进行空值与异常保护）
 */
function fmtMoney(n?: number): string {
  const v = typeof n === 'number' ? n : 0
  try { return '¥' + (v / 100).toLocaleString('zh-CN', { maximumFractionDigits: 2 }) } catch { return '¥' + (v / 100).toFixed(2) }
}

/**
 * 函数级注释：格式化数字（去除小数）
 * @param n 数值（允许 undefined ）
 * @returns 本地化后的整数字符串
 * @throws 无显式抛出（内部进行空值与异常保护）
 */
function fmtNumber(n?: number): string {
  const v = typeof n === 'number' ? n : 0
  try { return v.toLocaleString('zh-CN') } catch { return String(v) }
}

/**
 * 函数级注释：将日期字符串转换为 ISO 字符串（与后端对齐）
 * @param s 日期字符串（形如 yyyy-MM-dd）
 * @returns ISO8601 字符串，或原字符串（解析失败时）
 * @throws 无显式抛出
 */
function toISODate(s: string): string {
  /**
   * 函数级注释：生成无时区的日期时间字符串
   * @param s 日期字符串（形如 yyyy-MM-dd）
   * @returns 返回形如 "yyyy-MM-ddT00:00:00" 的无时区时间，避免后端解析为 UTC 导致 PostgreSQL 'timestamp without time zone' 写入错误
   * @throws 无显式抛出
   */
  try {
    // 不使用 toISOString()，避免生成带 Z 的 UTC 时间；保留本地无时区格式
    return `${s}T00:00:00`
  } catch {
    return s
  }
}

/**
 * 函数级注释：加载今日营业额
 * @param merchantId 商户ID（可选）
 * @param storeId 门店ID（可选）
 * @returns Promise<void> 无返回值，成功后更新 today 状态
 * @throws 可能抛出网络或服务端异常，已在内部捕获并记录到 errorToday
 */
async function loadTodayTurnover(merchantId: string = '', storeId: string = ''): Promise<void> {
  loadingToday.value = true
  errorToday.value = ''
  try {
    const result = await PaymentService.getTodayTurnover(merchantId, storeId)
    if (isSuccess(result)) {
      today.value = result.data || null
    } else {
      errorToday.value = result?.message || '获取今日营业额失败'
    }
  } catch (e: any) {
    errorToday.value = e?.message || '获取今日营业额异常'
  } finally {
    loadingToday.value = false
  }
}

/**
 * 函数级注释：加载期间报表（日报/周报/月报）
 * @param req 报表查询参数（类型与后端 Controller 对齐）
 * @returns Promise<void> 无返回值，成功后更新 report 状态
 * @throws 可能抛出网络或服务端异常，已在内部捕获并记录到 errorReport
 */
async function loadReportForm(req: ReportFormRequest): Promise<void> {
  loadingReport.value = true
  errorReport.value = ''
  try {
    const result = await PaymentService.getReportForm(req)
    if (isSuccess(result)) {
      report.value = result.data || null
    } else {
      errorReport.value = result?.message || '获取报表数据失败'
    }
  } catch (e: any) {
    errorReport.value = e?.message || '获取报表数据异常'
  } finally {
    loadingReport.value = false
  }
}

/**
 * 函数级注释：加载平台首页数据（净营收）
 * @param date 查询日期（与后端 `dateTime` 对齐），默认为当前选择日期
 * @returns Promise<void> 无返回值，成功后更新 platform 状态
 * @throws 可能抛出网络或服务端异常，已在内部捕获并记录到 errorPlatform
 */
async function loadPlatformHomepage(date: string | Date): Promise<void> {
  loadingPlatform.value = true
  errorPlatform.value = ''
  try {
    const iso = typeof date === 'string' ? toISODate(date) : date
    const result = await PaymentService.getPlatformHomepage(iso)
    if (isSuccess(result)) {
      platform.value = result.data || null
    } else {
      errorPlatform.value = result?.message || '获取平台首页数据失败'
    }
  } catch (e: any) {
    errorPlatform.value = e?.message || '获取平台首页数据异常'
  } finally {
    loadingPlatform.value = false
  }
}

/**
 * 函数级注释：筛选条件变更回调
 * @returns void 无返回值，触发重新加载报表
 * @throws 无显式抛出
 */
function onFiltersChange(): void {
  loadReportForm({
    reportFormType: filters.reportFormType,
    selectDateTime: toISODate(filters.selectDate),
    merchantId: filters.merchantId,
    storeId: filters.storeId
  })
}

/**
 * 函数级注释：刷新所有数据（今日+报表）
 * @returns void 无返回值
 * @throws 无显式抛出
 */
function reloadAll(): void {
  loadTodayTurnover(filters.merchantId, filters.storeId)
  onFiltersChange()
  loadPlatformHomepage(filters.selectDate)
}

/**
 * 函数级注释：创建或返回图表实例
 * @param el 图表容器 DOM
 * @returns echarts.ECharts | null 图表实例
 * @throws 无显式抛出（空 DOM 时返回 null）
 */
function ensureChart(el: HTMLDivElement | null, existing: echarts.ECharts | null): echarts.ECharts | null {
  if (!el) return null
  if (existing) return existing
  return echarts.init(el, undefined, { renderer: 'canvas' })
}

/**
 * 函数级注释：生成线性渐变色
 * @param from 起始色（hex 或 rgba）
 * @param to 结束色（hex 或 rgba）
 * @returns echarts.LinearGradient 渐变对象
 */
function gradient(from: string, to: string) {
  return new echarts.graphic.LinearGradient(0, 0, 0, 1, [
    { offset: 0, color: from },
    { offset: 1, color: to }
  ])
}

/**
 * 函数级注释：格式化时间区间标签
 * @param start 开始时间字符串
 * @param end 结束时间字符串
 * @returns string 格式化后的标签
 */
function formatRangeLabel(start?: string, end?: string): string {
  // 为避免底部时间重叠，仅显示开始日期的 MM-DD 简短格式
  const s = (start || '').slice(0, 10)
  const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s)
  return m ? `${m[2]}-${m[3]}` : s
}

/**
 * 函数级注释：渲染收入趋势折线图
 * @returns void
 */
function renderIncomeChart(): void {
  incomeChart = ensureChart(incomeChartRef.value, incomeChart)
  if (!incomeChart || !report.value?.IncomeComparisonStatistics?.length) return
  const labels = report.value.IncomeComparisonStatistics.map(t => formatRangeLabel(t.StartTime, t.EndTime))
  // 后端金额单位为分，前端折线图需展示为元
  const data = report.value.IncomeComparisonStatistics.map(t => ((t.Amount || 0) / 100))
  const option: echarts.EChartsOption = {
    grid: { left: 40, right: 20, top: 30, bottom: 70 },
    tooltip: { 
      trigger: 'axis',
      // tooltip 数值格式化为人民币（使用已有 fmtMoney，转换回分）
      valueFormatter: (value: any) => fmtMoney(Math.round(((Array.isArray(value) ? value[0] : value) || 0) * 100))
    },
    dataZoom: [{ type: 'slider', bottom: 20, height: 16 }],
    xAxis: { type: 'category', data: labels, axisLabel: { color: '#6b7280', rotate: 45, hideOverlap: true, margin: 12 } },
    yAxis: { 
      type: 'value',
      name: '金额（元）',
      nameTextStyle: { color: '#6b7280' },
      axisLabel: { 
        color: '#6b7280',
        formatter: (value: number) => '¥' + Number(value).toFixed(2)
      }
    },
    series: [{
      type: 'line', smooth: true, symbol: 'circle', symbolSize: 6,
      lineStyle: { width: 2, color: '#2563eb' },
      itemStyle: { color: '#2563eb' },
      areaStyle: { color: gradient('rgba(37,99,235,0.35)', 'rgba(37,99,235,0.05)') },
      label: { show: false },
      data
    }]
  }
  incomeChart.setOption(option)
}

/**
 * 函数级注释：渲染分账对比折线图
 * @returns void
 */
function renderDividedChart(): void {
  dividedChart = ensureChart(dividedChartRef.value, dividedChart)
  if (!dividedChart || !report.value?.DividedAmountComparisonStatistics?.length) return
  const labels = report.value.DividedAmountComparisonStatistics.map(t => formatRangeLabel(t.StartTime, t.EndTime))
  // 后端金额单位为分，前端折线图需展示为元
  const data = report.value.DividedAmountComparisonStatistics.map(t => ((t.Amount || 0) / 100))
  const option: echarts.EChartsOption = {
    grid: { left: 40, right: 20, top: 30, bottom: 70 },
    tooltip: { 
      trigger: 'axis',
      // tooltip 数值格式化为人民币（使用已有 fmtMoney，转换回分）
      valueFormatter: (value: any) => fmtMoney(Math.round(((Array.isArray(value) ? value[0] : value) || 0) * 100))
    },
    dataZoom: [{ type: 'slider', bottom: 20, height: 16 }],
    xAxis: { type: 'category', data: labels, axisLabel: { color: '#6b7280', rotate: 45, hideOverlap: true, margin: 12 } },
    yAxis: { 
      type: 'value',
      name: '金额（元）',
      nameTextStyle: { color: '#6b7280' },
      axisLabel: { 
        color: '#6b7280',
        formatter: (value: number) => '¥' + Number(value).toFixed(2)
      }
    },
    series: [{
      type: 'line', smooth: true, symbol: 'circle', symbolSize: 6,
      lineStyle: { width: 2, color: '#10b981' },
      itemStyle: { color: '#10b981' },
      areaStyle: { color: gradient('rgba(16,185,129,0.35)', 'rgba(16,185,129,0.05)') },
      label: { show: false },
      data
    }]
  }
  dividedChart.setOption(option)
}

/**
 * 函数级注释：渲染优惠订单柱状图（折扣单 vs 总单）
 * @returns void
 */
function renderDiscountChart(): void {
  discountChart = ensureChart(discountChartRef.value, discountChart)
  if (!discountChart || !report.value?.DiscountedOrders?.length) return
  const labels = report.value.DiscountedOrders.map(t => formatRangeLabel(t.StartTime, t.EndTime))
  const discount = report.value.DiscountedOrders.map(t => (t.DiscountedOrderCount || 0))
  const total = report.value.DiscountedOrders.map(t => (t.OrderCount || 0))
  const option: echarts.EChartsOption = {
    grid: { left: 40, right: 20, top: 30, bottom: 70 },
    tooltip: { trigger: 'axis' },
    legend: { data: ['折扣单数', '总订单数'] },
    dataZoom: [{ type: 'slider', bottom: 20, height: 16 }],
    xAxis: { type: 'category', data: labels, axisLabel: { color: '#6b7280', rotate: 45, hideOverlap: true, margin: 12 } },
    yAxis: { type: 'value', axisLabel: { color: '#6b7280' } },
    series: [
      { type: 'bar', name: '折扣单数', barMaxWidth: 24, itemStyle: { color: '#f59e0b' }, label: { show: true, position: 'top' }, data: discount },
      { type: 'bar', name: '总订单数', barMaxWidth: 24, itemStyle: { color: '#6366f1' }, label: { show: true, position: 'top' }, data: total }
    ]
  }
  discountChart.setOption(option)
}

/**
 * 函数级注释：渲染新老顾客对比柱状图
 * @returns void
 */
function renderCustomerChart(): void {
  customerChart = ensureChart(customerChartRef.value, customerChart)
  if (!customerChart || !report.value?.CustomerComparisonStatistics?.length) return
  const labels = report.value.CustomerComparisonStatistics.map(c => formatRangeLabel(c.StartTime, c.EndTime))
  const news = report.value.CustomerComparisonStatistics.map(c => (c.NewCustomerCount || 0))
  const olds = report.value.CustomerComparisonStatistics.map(c => (c.OldCustomerCount || 0))
  const option: echarts.EChartsOption = {
    grid: { left: 40, right: 20, top: 30, bottom: 70 },
    tooltip: { trigger: 'axis' },
    legend: { data: ['新客', '老客'] },
    dataZoom: [{ type: 'slider', bottom: 20, height: 16 }],
    xAxis: { type: 'category', data: labels, axisLabel: { color: '#6b7280', rotate: 45, hideOverlap: true, margin: 12 } },
    yAxis: { type: 'value', axisLabel: { color: '#6b7280' } },
    series: [
      { type: 'bar', name: '新客', barMaxWidth: 24, itemStyle: { color: '#3b82f6' }, label: { show: true, position: 'top' }, data: news },
      { type: 'bar', name: '老客', barMaxWidth: 24, itemStyle: { color: '#10b981' }, label: { show: true, position: 'top' }, data: olds }
    ]
  }
  customerChart.setOption(option)
}

/**
 * 函数级注释：渲染渠道统计饼状占比图（微信/支付宝）
 * @returns void 无返回值
 * @throws 无显式抛出（当数据为空时直接返回）
 */
function renderChannelChart(): void {
  channelChart = ensureChart(channelChartRef.value, channelChart)
  if (!channelChart || !report.value) return
  const wechat = report.value.WechatAmount || 0
  const alipay = report.value.AlipayAmount || 0
  const option: echarts.EChartsOption = {
    tooltip: { trigger: 'item', formatter: (p: any) => `${p.name}: ${fmtMoney(p.value)} (${p.percent}%)` },
    legend: { bottom: 0, textStyle: { color: '#374151' } },
    series: [{
      type: 'pie', radius: ['40%', '65%'], center: ['50%', '45%'],
      label: { show: true, formatter: '{b}: {d}%'},
      labelLine: { smooth: true, length: 8, length2: 10 },
      data: [
        { name: '微信净收金额', value: wechat, itemStyle: { color: '#10b981' } },
        { name: '支付宝净收金额', value: alipay, itemStyle: { color: '#2563eb' } }
      ]
    }]
  }
  channelChart.setOption(option)
}

/**
 * 函数级注释：渲染收款码排行榜横向柱状图
 * @returns void
 */
/**
 * 函数级注释：统一渲染所有图表（数据就绪时调用）
 * @returns void
 */
function renderAllCharts(): void {
  renderIncomeChart()
  renderDividedChart()
  renderDiscountChart()
  renderCustomerChart()
  renderChannelChart()
}

/**
 * 函数级注释：释放所有图表资源
 * @returns void
 */
function disposeCharts(): void {
  ;[incomeChart, dividedChart, discountChart, customerChart, channelChart].forEach(ch => { ch?.dispose() })
  incomeChart = dividedChart = discountChart = customerChart = channelChart = null
}

/**
 * 函数级注释：窗口尺寸变化时调整图表尺寸
 * @returns void
 */
function resizeCharts(): void {
  ;[incomeChart, dividedChart, discountChart, customerChart, channelChart].forEach(ch => { ch?.resize() })
}

/**
 * 生命周期：onMounted
 * 说明：组件挂载后加载今日营业额与默认日报表数据。
 * 异常：调用失败时会在界面上显示错误文案。
 */
onMounted(() => {
  reloadAll()
  // 初始尝试渲染（可能数据尚未返回，watch 会再次触发）
  nextTick(() => renderAllCharts())
  window.addEventListener('resize', resizeCharts)
})

/**
 * 生命周期：onUnmounted
 * 说明：释放图表实例与监听。
 */
onUnmounted(() => {
  disposeCharts()
  window.removeEventListener('resize', resizeCharts)
})

/**
 * 监听：报表数据变化后重绘图表
 */
watch(report, (val) => {
  if (!val) { disposeCharts(); return }
  nextTick(() => renderAllCharts())
})
</script>

<style scoped>
/*
  文件级样式说明：
  - 使用响应式网格与卡片样式，强化数据视觉层次与可读性。
  - 仅使用原生 CSS，兼容 H5 环境；不依赖外部 UI 框架。
*/
.dashboard { padding: 16px; color: #1f2937; }
.header { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 16px; }
.title { font-size: 20px; font-weight: 600; }
.filters { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.field { display: flex; align-items: center; gap: 8px; background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 8px; padding: 8px 10px; }
.field input,.field select { border: none; background: transparent; outline: none; font-size: 14px; }
.btn { padding: 8px 14px; border: 1px solid #2563eb; color: #fff; background-color: #2563eb; border-radius: 8px; cursor: pointer; }
.btn:hover { background-color: #1d4ed8; }

.section { margin-top: 18px; }
.section-title { font-size: 16px; font-weight: 600; margin-bottom: 10px; }
.loading { color: #6b7280; }
.error { color: #dc2626; }
.empty { color: #6b7280; font-style: italic; }

.cards { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
@media (max-width: 1200px) { .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px) { .cards { grid-template-columns: 1fr; } }
.card { background: #ffffff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 12px; box-shadow: 0 1px 2px rgba(0,0,0,0.04); }
.card.emphasis { border-color: #2563eb; box-shadow: 0 2px 6px rgba(37,99,235,0.15); }
.card-label { font-size: 12px; color: #6b7280; }
.card-value { font-size: 20px; font-weight: 700; margin-top: 6px; color: #111827; }
.card-sub { font-size: 12px; color: #6b7280; margin-top: 2px; }

.table-wrap { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; background: #fff; border: 1px solid #e5e7eb; border-radius: 12px; overflow: hidden; }
.table th, .table td { padding: 10px 12px; border-bottom: 1px solid #e5e7eb; text-align: left; }
.table thead th { background: #f9fafb; font-weight: 600; font-size: 13px; color: #374151; }
.table tbody tr:hover { background: #f3f4f6; }
.table td.money { font-weight: 600; color: #111827; }

.grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
@media (max-width: 900px) { .grid { grid-template-columns: 1fr; } }
.panel { background: #fff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 12px; }
.panel-title { font-weight: 600; color: #374151; margin-bottom: 8px; }
.trend-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; }
.trend-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 12px; color: #4b5563; }
.trend-row .time { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.trend-row .value { font-weight: 600; color: #111827; }
.bar { width: 100%; height: 8px; background: #f3f4f6; border-radius: 999px; overflow: hidden; }
.bar > span { display: block; height: 100%; background: #2563eb; }
.bar.dual { display: flex; gap: 4px; }
.bar.dual > span { flex: 0 0 auto; height: 100%; }
.bar.dual > .blue { background: #3b82f6; }
.bar.dual > .green { background: #10b981; }
/* 排行榜样式：条形图列表 */
.ranking-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; }
.rank-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 12px; color: #4b5563; }
.rank-row .name { font-weight: 600; color: #111827; }
.rank-row .value { font-weight: 600; color: #111827; }
.rank-bar { width: 100%; height: 8px; background: #f3f4f6; border-radius: 999px; overflow: hidden; }
.rank-bar > span { display: block; height: 100%; background: #10b981; }

/* ECharts 图表容器 */
.echart { width: 100%; height: 260px; }
@media (max-width: 900px) { .echart { height: 220px; } }

/* 卡片图标与多色风格 */
.card-icon { margin-right: 6px; }
.card { position: relative; overflow: hidden; }
.card::before { content: ''; position: absolute; inset: 0; pointer-events: none; opacity: 0.06; }
.card.emphasis { box-shadow: 0 4px 18px rgba(0,0,0,0.06); }
.accent-primary { border-left: 4px solid #2563eb; }
.accent-success { border-left: 4px solid #16a34a; }
.accent-teal { border-left: 4px solid #14b8a6; }
.accent-danger { border-left: 4px solid #ef4444; }
.accent-warning { border-left: 4px solid #f59e0b; }
.accent-indigo { border-left: 4px solid #6366f1; }
.accent-info { border-left: 4px solid #0ea5e9; }
.accent-primary::before { background: linear-gradient(135deg, #2563eb 0%, transparent 60%); }
.accent-success::before { background: linear-gradient(135deg, #16a34a 0%, transparent 60%); }
.accent-teal::before { background: linear-gradient(135deg, #14b8a6 0%, transparent 60%); }
.accent-danger::before { background: linear-gradient(135deg, #ef4444 0%, transparent 60%); }
.accent-warning::before { background: linear-gradient(135deg, #f59e0b 0%, transparent 60%); }
.accent-indigo::before { background: linear-gradient(135deg, #6366f1 0%, transparent 60%); }
.accent-info::before { background: linear-gradient(135deg, #0ea5e9 0%, transparent 60%); }
</style>
